package com.lexue.articlesync.service;

import com.lexue.articlesync.entity.Article;
import com.lexue.articlesync.entity.Video;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.MutableDataSet;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * 文件上传服务
 */
@Slf4j
@Service
public class FileUploadService {
    
    @Value("${app.upload.dir:src/main/resources/static/images/uploads}")
    private String uploadDir;
    
    @Value("${server.port:8082}")
    private int serverPort;
    
    // 支持的图片格式
    private static final List<String> IMAGE_EXTENSIONS = Arrays.asList("jpg", "jpeg", "png", "gif", "bmp", "webp");
    
    // 支持的视频格式
    private static final List<String> VIDEO_EXTENSIONS = Arrays.asList("mp4", "avi", "mov", "wmv", "flv", "mkv", "webm");
    
    // 支持的文档格式
    private static final List<String> DOCUMENT_EXTENSIONS = Arrays.asList("md", "txt", "doc", "docx");
    
    // Markdown解析器配置
    private final Parser parser;
    private final HtmlRenderer renderer;
    
    public FileUploadService() {
        MutableDataSet options = new MutableDataSet();
        this.parser = Parser.builder(options).build();
        this.renderer = HtmlRenderer.builder(options).build();
    }
    
    /**
     * 上传Markdown文件并创建文章
     */
    public Article uploadMarkdownFile(MultipartFile file, String title, String tags, 
                                    Boolean isOriginal, Boolean joinActivity) throws IOException {
        
        validateFile(file, DOCUMENT_EXTENSIONS);
        
        // 读取文件内容
        String content = new String(file.getBytes(), "UTF-8");
        
        // 转换Markdown为HTML
        Node document = parser.parse(content);
        String htmlContent = renderer.render(document);
        
        // 保存文件
        String savedPath = saveFile(file, "documents");
        
        // 生成摘要（取前200个字符）
        String summary = generateSummary(content);
        
        // 创建文章对象
        return Article.builder()
                .title(title != null ? title : file.getOriginalFilename())
                .content(content)
                .htmlContent(htmlContent)
                .summary(summary)
                .tags(tags)
                .isOriginal(isOriginal != null ? isOriginal : true)
                .joinActivity(joinActivity != null ? joinActivity : false)
                .status(Article.ArticleStatus.DRAFT)
                .build();
    }
    
    /**
     * 上传视频文件并创建视频对象
     */
    public Video uploadVideoFile(MultipartFile file, String title, String description, 
                               String tags, Boolean isOriginal, Boolean joinActivity) throws IOException {
        
        validateFile(file, VIDEO_EXTENSIONS);
        
        // 保存文件
        String savedPath = saveFile(file, "videos");
        
        // 创建视频对象
        return Video.builder()
                .title(title != null ? title : file.getOriginalFilename())
                .description(description)
                .filePath(savedPath)
                .fileName(file.getOriginalFilename())
                .fileSize(file.getSize())
                .format(FilenameUtils.getExtension(file.getOriginalFilename()))
                .tags(tags)
                .isOriginal(isOriginal != null ? isOriginal : true)
                .joinActivity(joinActivity != null ? joinActivity : false)
                .status(Video.VideoStatus.DRAFT)
                .build();
    }
    
    /**
     * 上传封面图片
     */
    public String uploadCoverImage(MultipartFile file) throws IOException {
        validateFile(file, IMAGE_EXTENSIONS);
        String webPath = saveFile(file, "covers");
        return webPath;
    }
    
    /**
     * 上传缩略图
     */
    public String uploadThumbnail(MultipartFile file) throws IOException {
        validateFile(file, IMAGE_EXTENSIONS);
        String webPath = saveFile(file, "thumbnails");
        return webPath;
    }
    
    /**
     * 验证文件
     */
    private void validateFile(MultipartFile file, List<String> allowedExtensions) {
        if (file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
        
        String extension = FilenameUtils.getExtension(file.getOriginalFilename()).toLowerCase();
        if (!allowedExtensions.contains(extension)) {
            throw new IllegalArgumentException("不支持的文件格式: " + extension + 
                    "，支持的格式: " + String.join(", ", allowedExtensions));
        }
    }
    
    /**
     * 保存文件到指定目录
     */
    private String saveFile(MultipartFile file, String subDir) throws IOException {
        // 创建目录结构：images/uploads/subDir/年月日/
        String dateDir = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        Path uploadPath = Paths.get(uploadDir, subDir, dateDir);
        
        if (!Files.exists(uploadPath)) {
            Files.createDirectories(uploadPath);
        }
        
        // 生成唯一文件名
        String originalFilename = file.getOriginalFilename();
        String extension = FilenameUtils.getExtension(originalFilename);
        String filename = UUID.randomUUID().toString() + "." + extension;
        
        Path filePath = uploadPath.resolve(filename);
        
        // 保存文件
        Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
        
        log.info("文件保存成功: {}", filePath.toString());
        
        // 返回相对于static目录的Web访问路径
        return String.format("/images/uploads/%s/%s/%s", subDir, dateDir, filename);
    }
    
    /**
     * 生成文章摘要
     */
    private String generateSummary(String content) {
        if (content == null || content.trim().isEmpty()) {
            return "";
        }
        
        // 移除Markdown标记
        String plainText = content.replaceAll("#", "")
                .replaceAll("\\*", "")
                .replaceAll("_", "")
                .replaceAll("`", "")
                .replaceAll("\\[([^\\]]+)\\]\\([^\\)]+\\)", "$1")
                .trim();
        
        // 取前200个字符作为摘要
        if (plainText.length() > 200) {
            return plainText.substring(0, 200) + "...";
        }
        
        return plainText;
    }
    
    /**
     * 删除文件
     */
    public boolean deleteFile(String filePath) {
        try {
            Path path = Paths.get(uploadDir, filePath);
            return Files.deleteIfExists(path);
        } catch (IOException e) {
            log.error("删除文件失败: {}", filePath, e);
            return false;
        }
    }
    
    /**
     * 获取文件的Web访问路径
     */
    public String getWebAccessPath(String webPath) {
        // 如果webPath已经是以/开头的Web访问路径，直接返回
        if (webPath.startsWith("/")) {
            return webPath;
        }
        
        // 否则确保路径使用正斜杠
        String normalizedPath = webPath.replace("\\", "/");
        if (!normalizedPath.startsWith("/")) {
            normalizedPath = "/" + normalizedPath;
        }
        return normalizedPath;
    }
    
    /**
     * 获取文件的完整HTTP URL
     */
    public String getFullHttpUrl(String webPath) {
        String finalWebPath = getWebAccessPath(webPath);
        return String.format("http://localhost:%d%s", serverPort, finalWebPath);
    }
    
    /**
     * 检查文件是否存在
     */
    public boolean fileExists(String relativePath) {
        return Files.exists(Paths.get(uploadDir, relativePath));
    }
    
    /**
     * 获取文件大小
     */
    public long getFileSize(String relativePath) {
        try {
            return Files.size(Paths.get(uploadDir, relativePath));
        } catch (IOException e) {
            log.error("获取文件大小失败: {}", relativePath, e);
            return 0;
        }
    }
}